﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using JControlEx.Common;
using System.Collections;
using System.IO;
using JControlEx.InternalControls;
using Microsoft.CSharp;
using JControlEx.Tools;

namespace JControlEx
{
    /// <summary>
    /// ObjectViewer.xaml 的交互逻辑
    /// </summary>
    public partial class ObjectViewer : UserControl
    {
        #region Events

        /// <summary>
        /// 
        /// </summary>
        public event EventHandler<PropertyValueChangedEventArgs> OnPropertyValueChanged;

        #endregion

        #region DependencyProperties

        public static readonly DependencyProperty ViewModeProperty =
            DependencyProperty.Register("ViewerMode", typeof(ViewMode), typeof(ObjectViewer));

        public static readonly DependencyProperty ViewTypeProperty =
            DependencyProperty.Register("ViewType", typeof(ViewType), typeof(ObjectViewer));

        public static readonly DependencyProperty IsBoolAsCheckBoxProperty =
            DependencyProperty.Register("IsBoolAsCheckBox", typeof(bool), typeof(ObjectViewer));

        public static readonly DependencyProperty IsReadOnlyProperty =
            DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(ObjectViewer), new PropertyMetadata(OnIsReadOnlyChanged));

        public static readonly DependencyProperty ShowMemberLevelProperty =
            DependencyProperty.Register("ShowMemberLevel", typeof(ShowMemberLevel), typeof(ObjectViewer));

        public static readonly DependencyProperty PropertySortProperty =
            DependencyProperty.Register("PropertySort", typeof(PropertySortBy), typeof(ObjectViewer));

        /// <summary>
        /// Gets or sets the mode.
        /// </summary>
        public ViewMode ViewMode
        {
            get { return (ViewMode)GetValue(ViewModeProperty); }
            set { SetValue(ViewModeProperty, value); }
        }

        /// <summary>
        /// Gets or sets the view type.
        /// </summary>
        public ViewType ViewType
        {
            get { return (ViewType)GetValue(ViewTypeProperty); }
            set { SetValue(ViewTypeProperty, value); }
        }

        /// <summary>
        /// Gets or sets a bool value indicates that will show the boolean value with CheckBox or ComboBox.
        /// </summary>
        public bool IsBoolAsCheckBox
        {
            get { return (bool)GetValue(IsBoolAsCheckBoxProperty); }
            set { SetValue(IsBoolAsCheckBoxProperty, value); }
        }

        /// <summary>
        /// Gets or sets a bool value indicates whether the viewer is read only.
        /// </summary>
        public bool IsReadOnly
        {
            get { return (bool)GetValue(IsReadOnlyProperty); }
            set { SetValue(IsReadOnlyProperty, value); }
        }
        private static void OnIsReadOnlyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {

        }

        /// <summary>
        /// Gets or sets the show member level.
        /// </summary>
        public ShowMemberLevel ShowMemberLevel
        {
            get { return (ShowMemberLevel)GetValue(ShowMemberLevelProperty); }
            set { SetValue(ShowMemberLevelProperty, value); }
        }

        /// <summary>
        /// Gets or sets the property sort method.
        /// </summary>
        public PropertySortBy PropertySort
        {
            get { return (PropertySortBy)GetValue(PropertySortProperty); }
            set { SetValue(PropertySortProperty, value); }
        }

        #endregion

        public ObjectViewer()
        {
            InitializeComponent();
            DataContextChanged += new DependencyPropertyChangedEventHandler(ObjectViewer_DataContextChanged);
            InitDefaultValues();
        }

        void ObjectViewer_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            SetDataContextValue_Plain(e.OldValue, e.NewValue);
        }

        private void InitDefaultValues()
        {
            DisplayNameProvider = DefaultDisplayNameProvider;
            DateTimeProvider = DefaultDateTimeProvider;
            MemberPropertyProvider = new Func<Type, IList<MemberProperty>>(type => TypeMapConfig.GetValue(type));
        }

        private Dictionary<Type, IList<MemberProperty>> _typeMapConfig = ObjectToPanelConfiguration.Instance.MemberPropertyCache;
        /// <summary>
        /// Sets the config of this object window, this will override the ObjectToPanelConfiguration.Instance.MemberPropertyCache.
        /// </summary>
        public Dictionary<Type, IList<MemberProperty>> TypeMapConfig
        {
            private get
            {
                return _typeMapConfig;
            }
            set
            {
                this._typeMapConfig = value;
            }
        }

        /// <summary>
        /// Gets or sets the window that holds this control.
        /// </summary>
        public Window Me { get; set; }

        #region Providers
        /// <summary>
        /// Gets or sets a delegate used for getting display name of property.
        /// <para>
        /// This will used for all viewer mode. If the display name of member property is specific, ignore.
        /// </para>
        /// </summary>
        public Func<string, string> DisplayNameProvider { get; set; }

        /// <summary>
        /// Gets or sets a delegate used for getting datetime from long or string value.
        /// </summary>
        public Func<object, DateTime> DateTimeProvider { get; set; }

        /// <summary>
        /// Provides a delegate that can get member property list from a type.
        /// </summary>
        public Func<Type, IList<MemberProperty>> MemberPropertyProvider { get; set; }

        /// <summary>
        /// Provides a list of object that match the member.
        /// <para>
        /// Parent type of this property.
        /// </para>
        /// <para>
        /// The member property of this property.
        /// </para>
        /// </summary>
        public Func<Type, Type, MemberProperty, List<Object>> ResourceListProvider { get; set; }

        /// <summary>
        /// The upper-case replacer.
        /// </summary>
        private static System.Text.RegularExpressions.Regex UpperCaseReplaceRegex = new System.Text.RegularExpressions.Regex("[A-Z]");
        /// <summary>
        /// Default display name getter. Will split the property at upper-case letter.
        /// </summary>
        /// <param name="property">The name of the property.</param>
        /// <returns>The display text.</returns>
        private string DefaultDisplayNameProvider(string property)
        {
            return UpperCaseReplaceRegex.Replace(property, matches => " " + matches.Value).Trim() + ":";
        }

        /// <summary>
        /// Default datetime getter.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private DateTime DefaultDateTimeProvider(object value)
        {
            DateTime result = new DateTime();
            if (value is long)
            {
                result = new DateTime((long)value);
            }
            else if (value is string)
            {
                DateTime.TryParse((string)value, out result);
            }
            return result;
        }

        #endregion

        private void SetDataContextValue_Plain(object oldValue, object newValue)
        {
            switch (ViewMode)
            {
                case ViewMode.Automatically:
                    MemberPropertyProvider = Automatically_GetMemberProperties;
                    break;
                case ViewMode.UserConfig:
                    break;
                case ViewMode.AttributeSpecific:
                    break;
                default:
                    break;
            }

            if (newValue != null)
            {
                Content = GetCustomizedPanel(newValue.GetType(), MemberPropertyProvider(newValue.GetType())); 
            }
        }

        /// <summary>
        /// Property : get, set
        /// Field : No Get Set
        /// Method
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private IList<MemberProperty> Automatically_GetMemberProperties(Type type)
        {
            List<System.Reflection.PropertyInfo> propertyInfos = new List<System.Reflection.PropertyInfo>();
            switch (ShowMemberLevel)
            {
                case ShowMemberLevel.Property:
                    propertyInfos = type.GetProperties().ToList();
                    break;

                case ShowMemberLevel.Field:
                default:
                    break;
            }

            switch (PropertySort)
            {
                case PropertySortBy.Alphabeta:
                    propertyInfos.Sort((x, y) => x.Name.CompareTo(y.Name));
                    break;
                case PropertySortBy.ABMixedAttribute:
                    break;
                case PropertySortBy.RuntimeRandom:
                    break;
                case PropertySortBy.Property:
                    propertyInfos.Sort((x, y) => x.PropertyType.Name.CompareTo(y.PropertyType.Name));
                    break;
                default:
                    break;
            }
            return propertyInfos.Select(pi => new MemberProperty(pi.Name) { IsEditable = pi.CanWrite }).ToList();
        }


        /// <summary>
        /// Get a panel from a type and its list member property.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="memberProperties"></param>
        /// <returns></returns>
        private UIElement GetCustomizedPanel(Type type, IList<MemberProperty> memberProperties)
        {
            Grid grid = new Grid();
            grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(100, GridUnitType.Auto) });
            grid.ColumnDefinitions.Add(new ColumnDefinition());

            foreach (var item in memberProperties)
            {
                var propertyInfo = type.GetProperty(item.PropertyName);
                if (propertyInfo == null)
                {
                    continue;
                }

                RowDefinition row = new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) };
                if (item.IsFixVertical || (typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType) && propertyInfo.PropertyType.IsGenericType))
                {
                    row.Height = new GridLength(1, GridUnitType.Star);
                }
                grid.RowDefinitions.Add(row);

                Label lable = new Label();
                lable.Content = string.IsNullOrEmpty(item.DisplayName) ? (DisplayNameProvider == null ? item.PropertyName : DisplayNameProvider(item.PropertyName)) : item.DisplayName;
                lable.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Right;

                grid.Children.Add(lable);
                Grid.SetRow(lable, grid.RowDefinitions.Count - 1);
                Grid.SetColumn(lable, 0);

                UIElement typePanel = GetCustomizedControl(propertyInfo.PropertyType, item);
                if (typePanel == null)
                {
                    continue;
                }
                grid.Children.Add(typePanel);
                Grid.SetRow(typePanel, grid.RowDefinitions.Count - 1);
                Grid.SetColumn(typePanel, 1);
            }

            ScrollViewer viewer = new ScrollViewer();
            viewer.Content = grid;
            viewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
            return viewer;
        }

        /// <summary>
        /// Get a specific control from a member property.
        /// </summary>
        /// <param name="type">The PropertyType.</param>
        /// <param name="memberProperty"></param>
        /// <returns></returns>
        private UIElement GetCustomizedControl(Type type, MemberProperty memberProperty)
        {
            UIElement customizedControl = null;

            BindingMode mode = memberProperty.IsEditable ? BindingMode.TwoWay : BindingMode.OneWay;

            #region Bool Value
            if (type == typeof(bool))
            {
                if (IsBoolAsCheckBox)
                {
                    CheckBox checkBox = new CheckBox();
                    checkBox.SetBinding(CheckBox.IsCheckedProperty, new Binding(memberProperty.PropertyName) { Mode = mode });
                    checkBox.Name = memberProperty.PropertyName;
                    checkBox.Margin = new Thickness(3);
                    checkBox.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                    checkBox.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                    customizedControl = checkBox;
                }
                else
                {
                    ComboBox comboBox = new ComboBox();
                    comboBox.Items.Add(true);
                    comboBox.Items.Add(false);
                    comboBox.SetBinding(ComboBox.SelectedItemProperty, new Binding(memberProperty.PropertyName) { Mode = mode });
                    comboBox.Margin = new Thickness(3);
                    customizedControl = comboBox;
                }
            }
            #endregion
            #region Byte[] Value
            else if (type == typeof(byte[]))
            {
                DockPanel panel = new DockPanel();
                panel.LastChildFill = true;
                if (memberProperty.IsPicture)
                {
                    Image image = new Image();
                    image.SetBinding(Image.SourceProperty, new Binding(memberProperty.PropertyName) { Converter = new ByteImageConverter() });
                    image.Stretch = Stretch.None;
                    Border border = new Border();
                    border.BorderBrush = Brushes.Green;
                    border.BorderThickness = new Thickness(1);
                    border.Child = image;
                    border.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                    border.VerticalAlignment = System.Windows.VerticalAlignment.Center;

                    ControlTag tag = new ControlTag()
                    {
                        Target = image,
                        MemberProperty = memberProperty,
                    };

                    Button saveButton = new Button() { Content = "Save" };
                    saveButton.Tag = tag;
                    saveButton.Width = 50;
                    saveButton.MaxHeight = 30;
                    saveButton.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                    // Save image to local file.
                    saveButton.Click += (sender, e) =>
                        {
                            Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog();
                            if (sfd.ShowDialog() == true)
                            {
                                Button button = sender as Button;
                                MemberProperty memProperty = ((ControlTag)button.Tag).MemberProperty;

                                byte[] bytes = DataContext.GetType().GetProperty(memProperty.PropertyName).GetValue(DataContext, null) as byte[];
                                using (Stream stream = new MemoryStream(bytes))
                                {
                                    System.Drawing.Image.FromStream(stream).Save(sfd.FileName);
                                }
                            }

                        };

                    Button loadButtom = new Button() { Content = "Load" };
                    loadButtom.Tag = tag;
                    loadButtom.Width = 50;
                    loadButtom.MaxHeight = 30;
                    loadButtom.IsEnabled = memberProperty.IsEditable;
                    loadButtom.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                    // Open local image and synchronized to the DataContext.
                    loadButtom.Click += (sender, e) =>
                        {
                            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
                            if (ofd.ShowDialog() == true)
                            {
                                Button button = sender as Button;
                                MemberProperty memProperty = ((ControlTag)button.Tag).MemberProperty;
                                Image imageSource = ((ControlTag)button.Tag).Target as Image;

                                byte[] bytes = File.ReadAllBytes(ofd.FileName);

                                DataContext.GetType().GetProperty(memProperty.PropertyName).SetValue(DataContext, bytes, null);
                                imageSource.GetBindingExpression(Image.SourceProperty).UpdateTarget();
                            }
                        };

                    panel.Children.Add(saveButton);
                    panel.Children.Add(loadButtom);
                    panel.Children.Add(border);

                    DockPanel.SetDock(saveButton, Dock.Right);
                    DockPanel.SetDock(loadButtom, Dock.Right);
                    DockPanel.SetDock(border, Dock.Left);
                }
                else
                {
                    string[] ops = new string[] { "Hex", "Base64", "IntArray" };

                    StackPanel options = new StackPanel();
                    options.Orientation = memberProperty.IsFixVertical ? Orientation.Vertical : Orientation.Horizontal;
                    options.Tag = ops[0];

                    TextBox textBox = new TextBox();
                    textBox.IsReadOnly = !memberProperty.IsEditable;
                    textBox.SetBinding(TextBox.TextProperty, new Binding(memberProperty.PropertyName) { Converter = new ByteStringConverter(), ConverterParameter = options });
                    textBox.Margin = new Thickness(3);
                    if (memberProperty.IsFixVertical)
                    {
                        textBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
                        textBox.TextWrapping = TextWrapping.Wrap;
                        textBox.MaxHeight = 300;
                    }

                    // Checked a option.
                    RoutedEventHandler reh = (sender, e) =>
                        {
                            options.Tag = (sender as RadioButton).Name;
                            textBox.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
                        };
                    foreach (string op in ops)
                    {
                        RadioButton rb = new RadioButton();
                        rb.Content = op;
                        rb.Name = op;
                        if (op == options.Tag.ToString())
                        {
                            rb.IsChecked = true;
                        }
                        if (!memberProperty.IsFixVertical)
                        {
                            rb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                            rb.Margin = new Thickness(3, 0, 3, 0);
                        }
                        else
                        {
                            rb.Margin = new Thickness(3, 3, 3, 3);
                        }
                        rb.Checked += reh;
                        options.Children.Add(rb);
                    }


                    panel.Children.Add(options);
                    panel.Children.Add(textBox);

                    DockPanel.SetDock(options, Dock.Right);
                    DockPanel.SetDock(textBox, Dock.Left);
                }
                customizedControl = panel;
            }
            #endregion
            #region Enumeration Value
            else if (type.IsEnum)
            {
                ComboBox comboBox = new ComboBox();
                comboBox.ItemsSource = Enum.GetValues(type);
                comboBox.SetBinding(ComboBox.SelectedItemProperty, new Binding(memberProperty.PropertyName) { Mode = mode });
                comboBox.Margin = new Thickness(3);
                comboBox.IsReadOnly =  !memberProperty.IsEditable;
                customizedControl = comboBox;
            }
            #endregion
            #region Delegate
            else if (type.IsSubclassOf(typeof(Delegate)))
            {
                StackPanel stackPanel = new StackPanel();

                DockPanel panel = new DockPanel();
                panel.LastChildFill = true;
                panel.Margin = new Thickness(3);

                var methodInfo = type.GetMethod("Invoke");
                var param = methodInfo.GetParameters();
                var returnType = methodInfo.ReturnType;

                Dictionary<string, Type> paramsList = new Dictionary<string, Type>();
                foreach (var item in param)
                {
                    paramsList.Add(item.Name, item.ParameterType);
                }
                object paramClass = ClassBuilder.GetClassInstance(memberProperty.PropertyName + "_Class", paramsList);
                ObjectViewer viewer = new ObjectViewer();
                viewer.DisplayNameProvider = str => str + "(" + param.Single(mi => str == mi.Name).ParameterType.Name + "):";
                viewer.DataContext = paramClass;

                Button buttonExcute = new Button();
                buttonExcute.Content = "Excute";
                ToolTip toolTip = new ToolTip();
                toolTip.Content = "Delegate is null.";
                toolTip.PlacementTarget = buttonExcute;
                toolTip.StaysOpen = false;
                ControlTag tag = new ControlTag()
                {
                    Source = viewer,
                    MemberProperty = memberProperty,
                    ObjectType = type
                };

                panel.Children.Add(buttonExcute);
                panel.Children.Add(viewer);

                DockPanel.SetDock(viewer, Dock.Left);
                DockPanel.SetDock(buttonExcute, Dock.Right);

                stackPanel.Orientation = Orientation.Vertical;
                stackPanel.Children.Add(panel);

                ObjectViewer resViewer = null;
                if (!returnType.Name.Equals("void", StringComparison.CurrentCultureIgnoreCase))
                {
                    Dictionary<string, Type> retList = new Dictionary<string, Type>()
                    {
                        { "Result", returnType }
                    };
                    object retClass = ClassBuilder.GetClassInstance("Return_Class", retList);
                    resViewer = new ObjectViewer();
                    resViewer.DisplayNameProvider = str => str + "(" + returnType.Name + "):";
                    resViewer.DataContext = retClass;
                    resViewer.IsReadOnly = true;
                    resViewer.Margin = new Thickness(3);

                    stackPanel.Children.Add(resViewer);

                    tag.Target = resViewer;
                }

                buttonExcute.Tag = tag;
                buttonExcute.Click += (sender, e) =>
                    {
                        object[] methodParams = param.Select(mi =>
                            viewer.DataContext.GetType().GetProperty(mi.Name).GetValue(viewer.DataContext, null)).ToArray();

                        object dlg = DataContext.GetType().GetProperty(memberProperty.PropertyName).GetValue(DataContext, null);

                        if (dlg != null)
                        {
                            object res = methodInfo.Invoke(dlg, methodParams);
                            if (resViewer != null && res != null)
                            {
                                Object temp = resViewer.DataContext;
                                temp.GetType().GetProperty("Result").SetValue(temp, res, null);
                                resViewer.DataContext = null;
                                resViewer.DataContext = temp;
                            } 
                        }
                        else
                        {
                            toolTip.IsOpen = true;
                        }
                    };


                customizedControl = stackPanel;
            }
            #endregion
            #region DateTime Value
            else if (((type == typeof(long) || type == typeof(string)) && memberProperty.IsDateTime) || type == typeof(DateTime))
            {
                DockPanel panel = new DockPanel();
                panel.LastChildFill = true;

                IValueConverter converter = null;
                if (type != typeof(DateTime))
                {
                    converter = new DateTimeConverter(DateTimeProvider);
                }

                Dameer dateTimePicker = new Dameer();
                dateTimePicker.ShowCheckBox = false;
                dateTimePicker.Format = DateTimePickerFormat.Custom;
                dateTimePicker.IsEnabled = memberProperty.IsEditable;
                dateTimePicker.SetBinding(Dameer.ValueProperty, new Binding(memberProperty.PropertyName) { Mode = mode, Converter = converter });
                dateTimePicker.Margin = new Thickness(3);

                Button nowButton = new Button();
                nowButton.Content = "Now";
                nowButton.Margin = new Thickness(3);
                nowButton.IsEnabled = memberProperty.IsEditable;
                // Set the datetime to Now.
                nowButton.Click += (sender, e) =>
                {
                    DataContext.GetType().GetProperty(memberProperty.PropertyName).SetValue(DataContext, DateTime.Now, null);
                    dateTimePicker.GetBindingExpression(Dameer.ValueProperty).UpdateTarget();
                };
                panel.Children.Add(dateTimePicker);
                panel.Children.Add(nowButton);
                panel.Children.Add(new TextBlock());

                DockPanel.SetDock(nowButton, Dock.Right);

                customizedControl = panel;
            }
            #endregion
            #region .Net Framework Value
            else if (type.IsPrimitive || type == typeof(string))
            {

                TextBox textBox = new TextBox();
                textBox.SetBinding(TextBox.TextProperty, new Binding(memberProperty.PropertyName) { Mode = mode });
                textBox.Name = memberProperty.PropertyName;
                textBox.Margin = new Thickness(3);
                textBox.IsReadOnly = !memberProperty.IsEditable;
                if (memberProperty.IsFixVertical)
                {
                    textBox.TextWrapping = TextWrapping.Wrap;
                    textBox.MinHeight = 80;
                    textBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
                }
                customizedControl = textBox;
            }
            #endregion
            #region Collection Value
            else if (typeof(IEnumerable).IsAssignableFrom(type))
            {
                Grid grid = new Grid();

                DockPanel dockPanel = new DockPanel();
                dockPanel.LastChildFill = true;

                ListBox listBox = new ListBox();
                listBox.Name = memberProperty.PropertyName;
                listBox.SetBinding(ListBox.ItemsSourceProperty, memberProperty.PropertyName);
                // Delete an item from the ListBox.
                listBox.KeyDown += (sender, e) =>
                    {
                    };
                // Show an item from the ListBox.
                listBox.MouseDoubleClick += (sender, e) =>
                    {
                    };
                listBox.Margin = new Thickness(3);
                listBox.VerticalAlignment = VerticalAlignment.Stretch;
                listBox.MinHeight = 50;
                listBox.Tag = new ControlTag()
                {
                    MemberProperty = memberProperty
                };

                DockPanel comboBoxDockPanel = new DockPanel();
                comboBoxDockPanel.LastChildFill = true;

                ComboBox comboBox = new ComboBox();
                comboBox.Margin = new Thickness(3);
                comboBox.Tag = new ControlTag()
                {
                    ObjectType = type
                };

                if (type.IsGenericType)
                {
                    Type[] param = type.GetGenericArguments();
                    Type first = param[0];
                    if (first.IsPrimitive || first == typeof(string))
                    {
                        comboBox.IsEditable = true;
                        comboBox.KeyDown += (sender , e) =>
                            {
                            };
                    }
                    else
                    {
                        var tag = new ControlTag()
                        {
                            Source = comboBox,
                            Target = listBox,
                            ObjectType = first,
                            MemberProperty = memberProperty
                        };
                        // Query all related resources.
                        comboBox.DropDownOpened += (sender, e) =>
                            {
                            };
                        comboBox.Tag = tag; 

                        Button button = new Button();
                        button.Content = "+";
                        button.Tag = tag;
                        button.SetBinding(Button.WidthProperty, new Binding("ActualHeight") { RelativeSource = new RelativeSource(RelativeSourceMode.Self) }); 
                        button.Margin = new Thickness(3);
                        // Add new item.
                        button.Click += (sender, e) =>
                            {
                            };

                        comboBoxDockPanel.Children.Add(button);
                        DockPanel.SetDock(button, Dock.Right);
                    }
                    comboBoxDockPanel.Children.Add(comboBox);

                    dockPanel.Children.Add(comboBoxDockPanel);
                    dockPanel.Children.Add(listBox);

                    DockPanel.SetDock(comboBoxDockPanel, Dock.Top);

                    customizedControl = dockPanel;
                }
            }
            #endregion
            #region User Classes Value
            else
            {

            }
            #endregion

            if (memberProperty.IsHighlight && customizedControl is Control)
            {
                (customizedControl as Control).BorderBrush = Brushes.Orange;
            }
            return customizedControl;
        }
    }
}
